'use strict';
const BaseService = require('./base');
const ResponseUtil = require('../utils/ResponseUtil');
const VRCE = require('../utils/ViewResultCodeEnum');
const RCEM = require('../utils/ResultCodeEnumMsg');
const Constant = require('../config/Constant');

class SysMenuService extends BaseService {


    async selectMenuPermsByUserId(userId) {
        let sql = `
                   select distinct m.perms
		from sys_menu m
			 left join sys_role_menu rm on m.menu_id = rm.menu_id
			 left join sys_user_role ur on rm.role_id = ur.role_id
			 left join sys_role r on r.role_id = ur.role_id
		where m.status = 0 and r.status = 0 and ur.user_id = ?
                  `;
        let result = await this.executeSql(sql, [userId]);
        let respSet = new Set();
        for (let i = 0; i < result.length; i++) {
            let item = result[i];
            if (item.perms)
                respSet.add(item.perms);
        }
        let respList = Array.from(respSet);
        return respList;
    }


    async selectMenuList({menuName, visible, status}) {
        let sql = `  select menu_id, menu_name, parent_id, order_num, path, is_frame, menu_type, visible, status, ifnull(perms,'') as perms, create_time, create_by, create_by_id, update_by, update_by_id, update_time, remark, del_flag
                        from sys_menu where 1=1 `;

        let wheres = [
            {column: 'menu_name', value: menuName, options: {condition: 'like'}},
            {column: 'visible', value: visible},
            {column: 'status', value: status}
        ];

        let formatSqlResult = this.formatSqlWhere(sql, wheres);

        sql = formatSqlResult[0];

        sql += ` order by parent_id, order_num`;
        let result = await this.executeSql(sql, formatSqlResult[1]);
        return result;
    }

    async selectMenuListByUserId({queryUserId, menuName, visible, status}) {
        let sql = `
                  select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.menu_type, m.order_num, m.create_time
                    from sys_menu m
                    left join sys_role_menu rm on m.menu_id = rm.menu_id
                    left join sys_user_role ur on rm.role_id = ur.role_id
                    left join sys_role ro on ur.role_id = ro.role_id
                    where ur.user_id = ${queryUserId}
                  `;
        let wheres = [
            {column: 'menu_name', value: menuName, options: {condition: 'like'}},
            {column: 'visible', value: visible},
            {column: 'status', value: status}
        ];

        let formatSqlResult = this.formatSqlWhere(sql, wheres);

        sql = formatSqlResult[0];
        sql += ` order by parent_id, order_num`;

        let result = await this.executeSql(sql, formatSqlResult[1]);
        return result;
    }


    async selectMenuTreeAll() {
        let sql = `
                    select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame as frame, m.menu_type, m.order_num, m.create_time
                        from sys_menu m where m.menu_type in ('M', 'C') and m.status = 0
                        order by m.parent_id, m.order_num
                  `
        let result = await this.executeSql(sql);
        return result;
    }


    async selectMenuTreeByUserId(userId) {
        let sql = `
                    select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame as frame, m.menu_type, m.order_num, m.create_time
                     from sys_menu m
                     left join sys_role_menu rm on m.menu_id = rm.menu_id
                     left join sys_user_role ur on rm.role_id = ur.role_id
                     left join sys_role ro on ur.role_id = ro.role_id
                     left join sys_user u on ur.user_id = u.user_id
                     where u.user_id = ? and m.menu_type in ('M', 'C') and m.status = 0  AND ro.status = 0
                     order by m.parent_id, m.order_num
                  `;
        let result = await this.executeSql(sql,[userId]);
        return result;
    }

    /**
     * 得到子节点列表
     */
    getChildList(list, t) {
        let tlist = [];
        if (Array.isArray(list) && list.length > 0) {
            const it = list[Symbol.iterator]();
            let n = it.next();
            while (n.done === false) {

                if (n.value && t.value && n.value.parentId === t.value.menuId) {
                    //n.value.children = [];
                    tlist.push(n.value)
                } else if (n.value && n.value.parentId === t.menuId) {
                    tlist.push(n.value)
                }
                n = it.next();
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    hasChild(list, t) {
        let childList = this.getChildList(list, t);
        if (childList.length > 0) {
            return true;
        }
        return false;
    }

    /**
     * 递归列表
     *
     * @param list
     * @param t
     */
    recursionFn(list, t) {
        let childList = this.getChildList(list, t);
        t.children = childList;
        for (let i = 0; i < childList.length; i++) {
            if (this.hasChild(list, childList[i])) {
                let cchildList = this.recursionFn(list, childList[i]);

                childList[i].children = cchildList;
            }
        }
        return childList;
    }

    /**
     * 根据父节点的ID获取所有子节点
     *
     * @param list     分类表
     * @param parentId 传入的父节点ID
     * @return String
     */
    getChildPerms(list, parentId) {
        let returnList = [];


        const it = list[Symbol.iterator]();


        let t = it.next();

        while (t.done === false) {

            if (t.value && t.value.parentId === parentId) {
                this.recursionFn(list, t);
                let obj = t.value;
                if (obj) {
                    obj.children = t.children;
                    returnList.push(obj);
                }
            }
            t = it.next();
        }
        return returnList;
    }

    async getMenus() {
        let loginUserInfo = this.ctx.getLoginInfo();
        let operatorType = loginUserInfo.operatorType;
        let operatorId = loginUserInfo.operatorId;
        let isAdmin = loginUserInfo.isAdmin;
        if (!loginUserInfo || !operatorType || !operatorId) {
            let res = ResponseUtil.resError(RCEM.NO_PERMISSION[1], RCEM.NO_PERMISSION[0]);
            return this.ctx.body = ResponseUtil.success(res);
        }

        let menus = [];

        if (isAdmin) {
            menus = await this.selectMenuTreeAll();
        } else {
            menus = await this.selectMenuTreeByUserId(operatorId);
        }
        return this.getChildPerms(menus, 0);
    }


    async getMenuList(query) {
        let loginUserInfo = this.ctx.getLoginInfo();
        let operatorType = loginUserInfo.operatorType;
        let operatorId = loginUserInfo.operatorId;
        let isAdmin = loginUserInfo.isAdmin;
        if (!loginUserInfo || !operatorType || !operatorId) {
            let res = ResponseUtil.resError(RCEM.NO_PERMISSION[1], RCEM.NO_PERMISSION[0]);
            return this.ctx.body = ResponseUtil.success(res);
        }

        let menuList = [];

        if (isAdmin) {
            menuList = await this.selectMenuList(query);
        } else {
            query.queryUserId = operatorId;
            menuList = await this.selectMenuListByUserId(query);
        }
        return menuList;
    }

    /**
     * 构建前端所需要树结构
     *
     * @param menus 菜单列表
     * @return 树结构列表
     */

    async buildMenuTree(menus) {
        let returnList = [];

        let tempList = [];

        menus.map(function (item) {
            tempList.push(item.menuId)
        });

        const it = menus[Symbol.iterator]();
        let menu = it.next();
        while (menu.done === false) {

            if (menu.value && !tempList.includes(menu.value.parentId)) {
                this.recursionFn(menus, menu);
                let obj = menu.value;
                if (obj) {
                    obj.children = menu.children;
                    returnList.push(obj);
                }
            }
            menu = it.next();
        }

        if (returnList.length === 0) {
            returnList = menus;
        }
        return returnList;
    }


    async checkMenuNameUnique(menu) {
        let menuId = menu.menuId || 0;
        let menuName = menu.menuName;
        let parentId = menu.parentId;
        let sql = ` select menu_id, menu_name, parent_id, order_num, path, is_frame, menu_type, visible, status, ifnull(perms,'') as perms, create_time, create_by, create_by_id, update_by, update_by_id, update_time, remark, del_flag
		from sys_menu where menu_name=? and parent_id=? limit 1`;
        let info = await this.executeSqlFirst(sql, [menuName, parentId]);
        if (info != null && info.menuId != menuId) {
            return Constant.NOT_UNIQUE;
        }
        return Constant.UNIQUE;
    }

    async selectMenuById(menuId) {
        let sql = `  select menu_id, menu_name, parent_id, order_num, path, is_frame, menu_type, visible, status, ifnull(perms,'') as perms, create_time, create_by, create_by_id, update_by, update_by_id, update_time, remark, del_flag
		from sys_menu where menu_id=? `;
        let result = await this.executeSqlFirst(sql, [menuId]);
        return result;
    }

    async insertMenu(menu) {
        let loginUserInfo = this.ctx.getLoginInfo();
        let operatorType = loginUserInfo.operatorType;
        let operatorId = loginUserInfo.operatorId;
        let createBy = loginUserInfo.createBy;
        if (!loginUserInfo || !operatorType || !operatorId) {
            let res = ResponseUtil.resError(RCEM.NO_PERMISSION[1], RCEM.NO_PERMISSION[0]);
            return this.ctx.body = ResponseUtil.success(res);
        }

        if (Constant.NOT_UNIQUE === (await this.checkMenuNameUnique(menu))) {
            return ResponseUtil.resError(VRCE.ADMIN_MENU_EXIST[1], VRCE.ADMIN_MENU_EXIST[0]);
        }

        if (0 != menu.parentId && null == (await this.selectMenuById(menu.parentId))) {
            return ResponseUtil.resError(VRCE.ADMIN_PARENT_MENU_NOT_EXIST[1], VRCE.ADMIN_PARENT_MENU_NOT_EXIST[0]);
        }

        let conn = await this.app.mysql;

        let params = {
            menu_name: menu.menuName,
            parent_id: menu.parentId,
            order_num: menu.orderNum,
            path: menu.path,
            is_frame: menu.frame || 0,
            menu_type: menu.menuType,
            visible: menu.visible || 0,
            status: menu.status || 0,
            perms: menu.perms,
            del_flag: 0,
            create_by: createBy,
            create_by_id: operatorId,
            create_time: new Date(),
            update_time: new Date()
        };

        let insertResult = await conn.insert('sys_menu', params);

        return insertResult.insertId;
    }

    async deleteRoleMenuByRoleId(roleId, conn) {
        let sql = ` delete
        from sys_role_menu
        where role_id = ?`;
        let size = await this.executeSqlSucc(sql, [roleId], conn);
        return size;
    }

    async updateMenu(menu) {
        let loginUserInfo = this.ctx.getLoginInfo();
        let operatorType = loginUserInfo.operatorType;
        let operatorId = loginUserInfo.operatorId;
        let createBy = loginUserInfo.createBy;
        if (!loginUserInfo || !operatorType || !operatorId) {
            let res = ResponseUtil.resError(RCEM.NO_PERMISSION[1], RCEM.NO_PERMISSION[0]);
            return this.ctx.body = ResponseUtil.success(res);
        }

        if (Constant.NOT_UNIQUE === (await this.checkMenuNameUnique(menu))) {
            return ResponseUtil.resError(VRCE.ADMIN_MENU_EXIST[1], VRCE.ADMIN_MENU_EXIST[0]);
        }

        if (0 != menu.parentId && null == (await this.selectMenuById(menu.parentId))) {
            return ResponseUtil.resError(VRCE.ADMIN_PARENT_MENU_NOT_EXIST[1], VRCE.ADMIN_PARENT_MENU_NOT_EXIST[0]);
        }

        if (menu.menuId === menu.parentId) {
            return ResponseUtil.resError(VRCE.ADMIN_MENU_SELECT_ERROR[1], VRCE.ADMIN_MENU_SELECT_ERROR[0]);
        }

        let conn = await this.app.mysql;

        let params = {
            menu_name: menu.menuName,
            parent_id: menu.parentId,
            order_num: menu.orderNum,
            path: menu.path,
            is_frame: menu.frame || 0,
            menu_type: menu.menuType,
            visible: menu.visible || 0,
            status: menu.status || 0,
            perms: menu.perms,
            update_by: createBy,
            update_by_id: operatorId,
            update_time: new Date()
        };

        const options = {
            where: {
                menu_id: menu.menuId
            }
        };

        console.log(params)
        let insertResult = await conn.update('sys_menu', params, options);

        return menu.menuId;
    }

    async hasChildByMenuId(menuId) {
        let sql = `select count(1) as count from sys_menu where parent_id = ?  `;
        let result = await this.executeSqlFirst(sql, [menuId]);
        return result ? result.count || 0 : 0;
    }


    async deleteMenuById(menuId) {
        let c = await this.hasChildByMenuId(menuId);
        if (c > 0) {
            return ResponseUtil.resError(VRCE.ADMIN_SUB_MENU_EXIST[1], VRCE.ADMIN_SUB_MENU_EXIST[0]);
        }

        let r = await this.ctx.service.sysRoleMenu.checkMenuExistRole(menuId);
        if (r > 0) {
            return ResponseUtil.resError(VRCE.ADMIN_FP_MENU_EXIST[1], VRCE.ADMIN_FP_MENU_EXIST[0]);
        }
        let sql = 'delete from sys_menu where menu_id = ?';
        let size = await this.executeSqlSucc(sql, [menuId]);
        return size;
    }

    async selectMenuListByRoleId(roleId) {
        let sql = `	select m.menu_id
		from sys_menu m
            left join sys_role_menu rm on m.menu_id = rm.menu_id
        where rm.role_id = ?
		order by m.parent_id, m.order_num`;
        let result = await this.executeSql(sql, [roleId]);
        let list = [];
        result.map(function (item) {
            list.push(item.menuId);
        });
        return list;
    }


}

module.exports = SysMenuService;
